package org.walkerljl.commons.designer;

import org.walkerljl.commons.util.CollectionUtils;
import org.walkerljl.commons.util.ListUtils;

import java.util.*;
import java.util.concurrent.ExecutorService;

class TaskExecuteEngineBuilder<Event> {

    private final TaskStructure<Event> taskStructure;

    private final ExecutorService executorService;

    private IdentityHashMap<EventHandler<Event>, Task<Event>> processPrototypeMap = new IdentityHashMap<EventHandler<Event>, Task<Event>>();

    TaskExecuteEngineBuilder(TaskStructure<Event> taskStructure, ExecutorService executorService) {
        this.taskStructure = taskStructure;
        this.executorService = executorService;
        init();
    }

    /**
     * 初始化依赖关系
     */
    private void init() {
        //被依赖的关系Map
        Map<EventHandler<Event>, List<EventHandler<Event>>> dependedHandlerMap = copyEventHandlerMap(taskStructure
                .getDenpendedEventHandlers());
        //依赖的关系Map
        Map<EventHandler<Event>, List<EventHandler<Event>>> dependingHandlerMap = new HashMap<EventHandler<Event>, List<EventHandler<Event>>>();

        /**
         * 计算依赖关系Map的值
         */
        for (EventHandler<Event> eventHandler : dependedHandlerMap.keySet()) {
            dependingHandlerMap.put(eventHandler,
                    new ArrayList<EventHandler<Event>>(1));
        }
        for (Map.Entry<EventHandler<Event>, List<EventHandler<Event>>> entry : dependedHandlerMap.entrySet()) {
            List<EventHandler<Event>> dependedEventHandlers = entry.getValue();
            EventHandler<Event> eventHandler = entry.getKey();
            for (EventHandler<Event> dependedEventHandler : dependedEventHandlers) {
                dependingHandlerMap.get(dependedEventHandler).add(eventHandler);
           }
        }

        /**
         * 计算没有被任何EventHandler依赖的EventHandler，并让他们依赖EndingEventHandler
         */
        EndingEventHandler endingEventHandler = new EndingEventHandler();
        List<EventHandler<Event>> endingDependingHandlers = new ArrayList<EventHandler<Event>>(
                1);
        for (Map.Entry<EventHandler<Event>, List<EventHandler<Event>>> entry : dependedHandlerMap.entrySet()) {
            List<EventHandler<Event>> dependedEventHandlers = entry.getValue();
            if (CollectionUtils.isEmpty(dependedEventHandlers)) {
                EventHandler<Event> eventHandler = entry.getKey();
                endingDependingHandlers.add(eventHandler);
                dependedHandlerMap.get(eventHandler).add(endingEventHandler);
            }
        }
        dependedHandlerMap.put(endingEventHandler,
                new ArrayList<EventHandler<Event>>(0));
        dependingHandlerMap.put(endingEventHandler,
                endingDependingHandlers);

        /**
         * 计算得到最终的依赖关系Map
         */
        for (Map.Entry<EventHandler<Event>, List<EventHandler<Event>>> entry : dependedHandlerMap.entrySet()) {
            EventHandler<Event> eventHandler = entry.getKey();
            List<EventHandler<Event>> dependedEventHandlers = entry.getValue();
            Task<Event> task;
            int dependingEventHandlerAmount = dependingHandlerMap.get(eventHandler).size();
            if (eventHandler != endingEventHandler) {
                task = new Task<Event>(eventHandler, dependingEventHandlerAmount, dependedEventHandlers);
            } else {
                task = new EndingTask(eventHandler, dependingEventHandlerAmount,
                        dependedEventHandlers);
            }
            processPrototypeMap.put(eventHandler, task);
        }
    }

    private Map<EventHandler<Event>, List<EventHandler<Event>>> copyEventHandlerMap(
            Map<EventHandler<Event>, List<EventHandler<Event>>> handlerMap) {

        IdentityHashMap<EventHandler<Event>, List<EventHandler<Event>>> dest = new IdentityHashMap<EventHandler<Event>, List<EventHandler<Event>>>();
        for (EventHandler<Event> eventHandler : handlerMap.keySet()) {
            dest.put(eventHandler,
                    new ArrayList<EventHandler<Event>>(handlerMap
                            .get(eventHandler)));
        }
        return dest;
    }

    TaskExecuteEngine<Event> build(Event event, long timeout) {
        return build(event, timeout, null);
    }

    @SuppressWarnings("unchecked")
    TaskExecuteEngine<Event> build(Event event, long timeout,
                                   Callback<Event> callback) {
        IdentityHashMap<EventHandler<Event>, Task<Event>> taskMap = new IdentityHashMap<EventHandler<Event>, Task<Event>>(
                processPrototypeMap.size());
        TaskExecuteEngine<Event> taskExecuteEngine = new TaskExecuteEngine<Event>(event,
                executorService, taskMap, callback, timeout);
        for (Map.Entry<EventHandler<Event>, Task<Event>> entry : processPrototypeMap.entrySet()) {
            EventHandler<Event> eventHandler = entry.getKey();
            Task<Event> newTask = (Task<Event>) entry.getValue().clone();
            newTask.init(taskExecuteEngine, event);
            taskMap.put(eventHandler, newTask);
        }
        return taskExecuteEngine;
    }

    private class EndingTask extends Task<Event> {

        EndingTask(EventHandler<Event> eventHandler, int depdendingAmount,
                              List<EventHandler<Event>> dependedEventHandlers) {
            super(eventHandler, depdendingAmount, dependedEventHandlers);
        }

        @Override
        public void run() {
            taskExecuteEngine.markAsCompleted();
        }
    }

    private class EndingEventHandler implements EventHandler<Event> {
        public void onEvent(Event event) {

        }
    }
}
